package net.esj.basic.plugins.struts2.dispatcher;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import net.esj.basic.core.engine.util.logging.Logger;
import net.esj.basic.core.engine.util.logging.LoggerFactory;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;

/**
 * 在原有JakartaMultiPartRequest处理类的基础上做了调整，解决在大并发下文件上传， 导致生成大量临时文件没有清理问题
 * 
 * 
 * @see net.melon.uploader.plugins.struts2.dispatcher.MelonMultiPartRequest
 */
@Deprecated
public class PerfMultiPartRequest extends JakartaMultiPartRequest {

	private static final Logger log = LoggerFactory
			.getLogger(PerfMultiPartRequest.class);
	
	public static final String UPLOAD_PERCENT_COUNTER = "_SES_UP_PER_COUNTER";

	/**
	 * 解析时在原有JakartaMultiPartRequest处理类的基础上做了两个调整，原有parse函数版权归apache的struts所有。
	 * 1.在处理附件时设置1M的内存，用于临时存放文件，避免每次都写文件。 原先struts：fac.setSizeThreshold(0);
	 * //原先原码里面还标明了直接写文件，但是不知道为啥这样做，不知道哪位达人清楚原因。 新调整为：fac.setSizeThreshold(1024
	 * * 1024); 2.对于formfield的项，解析完成就删除，不用遗留到最后用gc删除。遗留延迟删除会导致生成大量垃圾小文件。
	 * 
	 * 
	 * 新增：item.delete();
	 * 
	 * 20130625 新增:CountPercentListener 增加百分比计算功能
	 * 
	 * @param saveDir
	 *            the directory to save off the file
	 * @param servletRequest
	 *            the request containing the multipart
	 * @throws java.io.IOException
	 *             is thrown if encoding fails.
	 */
	public void parse(HttpServletRequest servletRequest, String saveDir)
			throws IOException {
		DiskFileItemFactory fac = new DiskFileItemFactory();
		fac.setSizeThreshold(1024 * 1024);
		if (saveDir != null) {
			fac.setRepository(new File(saveDir));
		}

		// Parse the request
		ServletFileUpload upload = new ServletFileUpload(fac);
		upload.setSizeMax(maxSize);
		upload.setProgressListener(new CountPercentListener(servletRequest.getSession()));
		servletRequest.setAttribute("maxSize", maxSize);
		List<FileItem> items = null;

		try {
			items = (List<FileItem>) upload
					.parseRequest(createRequestContext(servletRequest));
			for (Object item1 : items) {
				FileItem item = (FileItem) item1;
				String itemFieldName = item.getFieldName();
				if (log.isDebugEnabled()) {
					log.debug("Found item " + itemFieldName);
				}
				if (item.isFormField()) {
					log.debug("Item is a normal form field");
					List<String> values = params.get(itemFieldName);
					if (null == values) {
						values = new ArrayList<String>();
					}

					String charset = servletRequest.getCharacterEncoding();
					if (null == charset) {
						values.add(item.getString());
					} else {
						values.add(item.getString(charset));
					}

					params.put(itemFieldName, values);
					item.delete();
				} else {
					log.debug("Item is a file upload");

					// Skip file uploads that don't have a file name - meaning
					// that no file was selected.
					if (null == item.getName()
							|| item.getName().trim().length() < 1) {
						log.debug("No file has been uploaded for the field: "
								+ itemFieldName);
						continue;
					}

					List<FileItem> values = files.get(itemFieldName);
					if (null == values) {
						values = new ArrayList<FileItem>();
					}

					if (item.isInMemory()) {
						try {
							item.write(((DiskFileItem) item).getStoreLocation());
						} catch (Exception e) {
							log.warn("Unable to write item", e);
							errors.add(e.getMessage());
						}

					}
					values.add(item);
					files.put(itemFieldName, values);
				}
			}
		} catch (FileUploadException e) {
			log.warn("Unable to parse request", e);
			errors.add(e.getMessage());
		}

	}

	/**
	 * 由于parse需要此函数，但是JakartaMultiPartRequest类不允许子类访问，所以
	 * 这里又重新定义一遍。此方法沿用JakartaMultiPartRequest类的createRequestContext类处理， 没有做任何调整
	 * 
	 * @param req
	 *            the request.
	 * @return a new request context.
	 */
	private RequestContext createRequestContext(final HttpServletRequest req) {
		return new RequestContext() {
			public String getCharacterEncoding() {
				return req.getCharacterEncoding();
			}

			public String getContentType() {
				return req.getContentType();
			}

			public int getContentLength() {
				return req.getContentLength();
			}

			public InputStream getInputStream() throws IOException {
				InputStream inputStream = req.getInputStream();
				if (inputStream == null) {
					throw new IOException("Missing content in the request");
				}
				return req.getInputStream();
			}
		};
	}

	private static class CountPercentListener implements ProgressListener {

		private HttpSession session;

		public CountPercentListener(HttpSession session) {
			super();
			this.session = session;
		}

		@Override
		public void update(long arg0, long arg1, int arg2) {
			session.setAttribute(UPLOAD_PERCENT_COUNTER,
					(arg0 / (arg1 * 1.0)) * 100.0);
		}

	}

}

/**
 * public void preExecute() throws DVException { if (httpServletRequest
 * instanceof MultiPartRequestWrapper) { MultiPartRequestWrapper requestWrapper
 * = (MultiPartRequestWrapper) httpServletRequest;
 * 
 * if (requestWrapper.hasErrors()) { Collection<String> errors =
 * requestWrapper.getErrors(); if (errors != null && !errors.isEmpty()) {
 * Iterator iterator = errors.iterator(); long maxSize = 0; if
 * (requestWrapper.getAttribute("maxSize") != null) { maxSize =
 * Long.parseLong(requestWrapper.getAttribute("maxSize") .toString()); maxSize =
 * maxSize / 1024 / 1024; }
 * 
 * while (iterator.hasNext()) { String errorMess = (String) iterator.next();
 * log.warn(errorMess); throw new DVException(
 * ErrorNumber.Resource.RESOURCE_ADD_FILE_SIZE, new String[] {maxSize + ""}); }
 * } return; }
 * 
 * Enumeration<String> parameterNames = requestWrapper.getFileParameterNames();
 * while (parameterNames.hasMoreElements()) {
 * 
 * @SuppressWarnings("unused") String paramterName =
 *                             parameterNames.nextElement(); File[] files =
 *                             requestWrapper.getFiles(paramterName); if (null
 *                             == files || files.length == 0) { continue; } else
 *                             if (files.length == 1) { FileBean fileBean = new
 *                             FileBean();
 *                             fileBean.setAbsolutePath(files[0].getAbsolutePath
 *                             ()); fileBean.setFileSize(files[0].length());
 *                             fileBean.setFilename(requestWrapper.getFileNames(
 *                             paramterName)[0]); this.fileMap.put(paramterName,
 *                             fileBean); } else { ArrayList<FileBean> list =
 *                             new ArrayList(); for (int i = 0; i <
 *                             files.length; i++) { File file = files[i];
 *                             FileBean fileBean = new FileBean();
 *                             fileBean.setAbsolutePath(file.getAbsolutePath());
 *                             fileBean.setFileSize(file.length());
 *                             fileBean.setFilename
 *                             (requestWrapper.getFileNames(paramterName)[i]);
 *                             list.add(fileBean); }
 *                             this.fileMap.put(paramterName, list); } } } }
 **/
